﻿// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.AttributedModel;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.Internal;
using System.ComponentModel.Composition.ReflectionModel;

namespace System.ComponentModel.Composition.Caching.AttributedModel
{
    internal class CachedAttributedImportDefinition : ContractBasedImportDefinition
    {
        public CachedAttributedImportDefinition(IDictionary<string, object> cache)
        {
            Assumes.NotNull(cache);
            this.Cache = cache;
        }

        public IDictionary<string, object> Cache
        {
            get;
            private set;
        }

        public override string ContractName
        {
            get { return this.Cache.ReadValue<string>(AttributedCacheServices.CacheKeys.ContractName); }
        }

        public override ImportCardinality Cardinality
        {
            get { return this.Cache.ReadValue<ImportCardinality>(AttributedCacheServices.CacheKeys.Cardinality); }
        }

        public override bool IsPrerequisite
        {
            get { return this.Cache.ReadValue<bool>(AttributedCacheServices.CacheKeys.IsPrerequisite, false); }
        }

        public override bool IsRecomposable
        {
            get { return this.Cache.ReadValue<bool>(AttributedCacheServices.CacheKeys.IsRecomposable, false); }
        }

        public override IEnumerable<string> RequiredMetadata
        {
            get { return this.Cache.ReadEnumerable<string>(AttributedCacheServices.CacheKeys.RequiredMetadata); }
        }

        internal MemberInfo GetMember()
        {
            return (MemberInfo)this.Cache.LoadMember();
        }

        internal ParameterInfo GetParameter(ConstructorInfo constructor)
        {
            return this.Cache.LoadParameter(constructor);
        }

        public ImportingItem ToImportingItem(Func<ConstructorInfo> constructor)
        {
            MemberInfo member = GetMember();

            if (member != null)
            {
                return ToImportingMember(member);
            }

            return ToImportingParameter(constructor());
        }

        private ImportingMember ToImportingMember(MemberInfo member)
        {
            return new ImportingMember(this, member.ToReflectionWritableMember());
        }

        private ImportingParameter ToImportingParameter(ConstructorInfo constructor)
        {
            ParameterInfo parameter = GetParameter(constructor);

            return new ImportingParameter(this, new ReflectionParameter(parameter));
        }

        public static IDictionary<string, object> CreateCache(AttributedImportDefinition import)
        {
            Assumes.NotNull(import);

            IDictionary<string, object> cache = new Dictionary<string, object>();
            cache.WriteValue(AttributedCacheServices.CacheKeys.ContractName, import.ContractName);
            cache.WriteValue(AttributedCacheServices.CacheKeys.Cardinality, import.Cardinality);
            cache.WriteValue(AttributedCacheServices.CacheKeys.IsPrerequisite, import.IsPrerequisite, false);
            cache.WriteValue(AttributedCacheServices.CacheKeys.IsRecomposable, import.IsRecomposable, false);
            cache.WriteEnumerable(AttributedCacheServices.CacheKeys.RequiredMetadata, import.RequiredMetadata);

            AttributedMemberImportDefinition memberImport = import as AttributedMemberImportDefinition;
            if (memberImport != null)
            {
                cache.WriteMember(memberImport.Member);
            }
            else
            {
                cache.WriteParameter(((AttributedParameterImportDefinition)import).Parameter);
            }

            return cache;
        }
    }
}
